package com.huashi.dealer.modular.business.user.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huashi.dealer.commonEntity.*;
import com.huashi.dealer.core.component.DataScopeInfo;
import com.huashi.dealer.core.exception.CommonException;
import com.huashi.dealer.core.exception.ServiceException;
import com.huashi.dealer.core.util.BizAssertUtil;
import com.huashi.dealer.core.util.CaptchaUtil;
import com.huashi.dealer.core.util.PasswordUtil;
import com.huashi.dealer.core.util.RedisUtil;
import com.huashi.dealer.core.util.SaTokenUtil;
import com.huashi.dealer.core.util.TokenUtil;
import com.huashi.dealer.modular.business.address.param.AddressInfo;
import com.huashi.dealer.modular.business.balance.service.BalanceService;
import com.huashi.dealer.modular.business.message.service.MessageService;
import com.huashi.dealer.modular.business.order.service.OrderService;
import com.huashi.dealer.modular.business.address.mapper.UserAddressMapper;
import com.huashi.dealer.modular.business.user.mapper.*;
import com.huashi.dealer.modular.business.user.param.*;
import com.huashi.dealer.modular.business.user.service.UserService;
import com.huashi.dealer.modular.business.user.vo.StoreUserLoginVo;
import com.huashi.dealer.modular.business.user.vo.StoreUserListItemVo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.huashi.dealer.modular.business.user.param.StoreUserListRequest;
import com.huashi.dealer.modular.business.user.param.StoreUserSaveRequest;
import com.huashi.dealer.modular.business.user.vo.StatementAccountVo;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.Set;
import java.util.HashSet;

/**
 * API用户Service实现类
 *
 * @author 谭陈强
 * @since 2025-07-30
 */
@Service("apiUserServiceImpl")
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    @Autowired
    private RedisUtil redisUtil;
    
    @Autowired
    private TokenUtil tokenUtil;
    @Resource
    private OrderService orderService;
    
    @Resource
    private MessageService messageService;
    
    @Resource
    private StoreUserMapper storeUserMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private UserAddressMapper userAddressMapper;
    @Resource
    private BalanceService balanceService;

    @Resource
    private StoreRoleMapper storeRoleMapper;

    @Resource
    private StoreAccessMapper storeAccessMapper;

    @Resource
    private StoreUserRoleMapper storeUserRoleMapper;

    @Resource
    private StoreRoleAccessMapper storeRoleAccessMapper;
    @Autowired
    private UserService userService;
    @Resource
    private DataScopeInfo dataScopeInfo;
    @Autowired
    private StoreUserRuleMapper storeUserRuleMapper;

    @Override
    public UserInfo accountLogin(UserRequestParam requestParam) {
        UserInfo userInfo=new UserInfo();
        try {
            BizAssertUtil.notEmpty(requestParam.getCode(), 10003, "验证码不能为空");
            BizAssertUtil.notEmpty(requestParam.getAccount(), 10001, "账号不能为空");
            BizAssertUtil.notEmpty(requestParam.getPassword(), 10002, "密码不能为空");
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getAccount, requestParam.getAccount());
            User user = this.getOne(queryWrapper);
            
            if (user == null) {
                throw new ServiceException("账号不存在");
            }

            String encryptedPassword = PasswordUtil.yoshopHash(requestParam.getPassword());
            if (!encryptedPassword.equals(user.getPassword())) {
                throw new ServiceException("密码错误");
            }
            if (requestParam.getCode() != null && !requestParam.getCode().isEmpty()) {
                String redisCaptcha = (String) redisUtil.get(requestParam.getCode().toLowerCase());
                if (redisCaptcha == null || !requestParam.getCode().equalsIgnoreCase(redisCaptcha)) {
                    throw new ServiceException("验证码错误");
                }
                redisUtil.delete(requestParam.getCode().toLowerCase()); // 验证成功后删除验证码
            }


            // 使用Sa-Token登录
            String token = SaTokenUtil.login(user);
            // 更新用户token到数据库
            user.setToken(token);
            this.updateById(user);
            // 构建响应
            userInfo=buildUserInfo(user);
        } catch (Exception e) {
            throw new CommonException("登录失败：" + e.getMessage());
        }
        
        return userInfo;
    }

    @Override
    public UserResponseParam login(UserRequestParam requestParam) {
        UserResponseParam responseParam = new UserResponseParam();
        
        try {
            // TODO: 用户自动登录逻辑
            // 这里需要根据微信openId或其他方式自动登录
            
            // 模拟自动登录
            responseParam.setUserId(1L);
            responseParam.setToken("auto_token_" + System.currentTimeMillis());
            
        } catch (Exception e) {
            throw new CommonException("自动登录失败：" + e.getMessage());
        }
        
        return responseParam;
    }

    @Override
    public UserInfo getUserDetail(String token) {
        UserInfo responseParam = new UserInfo();
        Long userId = SaTokenUtil.getLoginId();
        if (userId == null) {
            throw new ServiceException(401,"用户未登录或Token已过期");
        }

        User user = this.getById(userId);
        if (user == null) {
            throw new ServiceException(401,"用户未登录或Token已过期");
        }
        try {
            if (token == null || token.isEmpty()) {
                throw new CommonException("用户令牌不能为空");
            }
            // 计算销售目标完成百分比
            String percentage = calculateSalesPercentage(user.getUserId(), user.getSalesMoney());
            // 处理消息通知逻辑
            Integer isMessage = messageService.calculateMessageStatus(user.getUserId().intValue());

            // 构建用户信息
            BeanUtil.copyProperties(user, responseParam);
            responseParam.setPercentage(percentage);
            responseParam.setIsMessage(isMessage);
            List<UserAddressVo> orderAddressList =userMapper.getOrderAddressListByUserId(user.getUserId());

            if(!orderAddressList.isEmpty()) {
                responseParam.setAddress(orderAddressList);
            }
            if (user.getAddressId() != null && user.getAddressId() != 0) {
                // 使用修复后的getDefaultAddress方法
                UserAddressVo defaultAddress = this.getDefaultAddress(user.getUserId());
                if (defaultAddress != null) {
                    responseParam.setAddressDefault(defaultAddress);
                    responseParam.setRegion(defaultAddress.getRegion());
                }
            }
            responseParam.setStoreUser(storeUserMapper.selectById(user.getStoreUserId()));

        } catch (Exception e) {
            throw new CommonException("获取用户详情失败：" + e.getMessage());
        }
        return responseParam;
    }
    private String calculateSalesPercentage(Long userId, BigDecimal salesMoney) {
        if (salesMoney == null || salesMoney.compareTo(BigDecimal.ZERO) <= 0) {
            return "0%";
        }

        // 使用MyBatis-Plus Lambda查询
        BigDecimal payPrice = orderService.getBaseMapper().selectMaps(new LambdaQueryWrapper<Order>()
                .select(Order::getPayPrice)
                .eq(Order::getUserId, userId)
                .eq(Order::getOrderStatus, 30)
                .eq(Order::getIsDelete, 0))
                .stream()
                .map(map -> (BigDecimal) map.get("pay_price"))
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        if (payPrice.compareTo(BigDecimal.ZERO) <= 0) {
            return "0%";
        }
        BigDecimal percentage = payPrice.divide(salesMoney, 4, RoundingMode.HALF_UP)
                .multiply(new BigDecimal("100"))
                .setScale(2, RoundingMode.HALF_UP);
        return percentage.compareTo(new BigDecimal("100")) >= 0 ?
                "100%" : percentage.setScale(2, RoundingMode.HALF_UP) + "%";
    }
    

    @Override
    public void editUserInfo(User requestParam) {
        try {
            Long userId = SaTokenUtil.getLoginId();
            if (userId == null) {
                throw new ServiceException("用户未登录");
            }

            // 判断用户类型
            if (SaTokenUtil.isDealer()) {
                // 经销商：只能编辑自己的信息
                User currentUser = this.getById(userId);
                if (currentUser == null) {
                    throw new ServiceException("用户不存在");
                }
            } else if (SaTokenUtil.isStoreUser()) {
                // 业务员：不能编辑用户信息，应该调用其他方法
                throw new ServiceException("业务员不能编辑用户信息");
            } else {
                throw new ServiceException("无权限编辑用户信息");
            }

//            LambdaUpdateWrapper<User> updateWrapper = getUserLambdaUpdateWrapper(requestParam, requestParam);

            // 如果包含密码，需要加密
            if (requestParam.getPassword() != null && !requestParam.getPassword().isEmpty()) {
                String encryptedPassword = PasswordUtil.yoshopHash(requestParam.getPassword());
//                updateWrapper.set(User::getPassword, encryptedPassword);
                requestParam.setPassword(encryptedPassword);
            }
            
            // 更新到数据库
            boolean updateResult = this.updateById(requestParam);
            if (!updateResult) {
                throw new ServiceException("更新用户信息失败");
            }
            
            // 更新会话中的用户信息
            User updatedUser = this.getById(userId);
            StpUtil.getSession().set("userInfo", updatedUser);
        }
        catch (Exception e) {
            throw new CommonException("更新用户信息失败：" + e.getMessage());
        }
    }

    private static LambdaUpdateWrapper<User> getUserLambdaUpdateWrapper(User requestParam, User user) {
        // 使用LambdaUpdateWrapper进行部分字段更新
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getUserId, user.getUserId());

        // 只更新传入的非null字段
        if (requestParam.getNickName() != null) {
            updateWrapper.set(User::getNickName, requestParam.getNickName());
        }
        if (requestParam.getAvatarUrl() != null) {
            updateWrapper.set(User::getAvatarUrl, requestParam.getAvatarUrl());
        }
        if (requestParam.getGender() != null) {
            updateWrapper.set(User::getGender, requestParam.getGender());
        }
        if (requestParam.getCountry() != null) {
            updateWrapper.set(User::getCountry, requestParam.getCountry());
        }
        if (requestParam.getProvinceId() != null) {
            updateWrapper.set(User::getProvinceId, requestParam.getProvinceId());
        }
        if (requestParam.getCityId() != null) {
            updateWrapper.set(User::getCityId, requestParam.getCityId());
        }
        if (requestParam.getRegionId() != null) {
            updateWrapper.set(User::getRegionId, requestParam.getRegionId());
        }
        if (requestParam.getAddressId() != null) {
            updateWrapper.set(User::getAddressId, requestParam.getAddressId());
        }
        if (requestParam.getMobile() != null) {
            updateWrapper.set(User::getMobile, requestParam.getMobile());
        }
        if (requestParam.getRealName() != null) {
            updateWrapper.set(User::getRealName, requestParam.getRealName());
        }
        if (requestParam.getAccount() != null) {
            updateWrapper.set(User::getAccount, requestParam.getAccount());
        }
        return updateWrapper;
    }

    @Override
    public UserResponseParam generateCode() {
        UserResponseParam responseParam = new UserResponseParam();
        
        try {
            String code = PasswordUtil.generateRandomCode(4);
            // 使用更兼容的验证码生成方式
            String imageBase64;
            try {
                imageBase64 = CaptchaUtil.generateCaptchaImage(code);
            } catch (Exception e) {
                // 如果字体生成失败，使用简单的验证码图片
                log.warn("验证码图片生成失败，使用备用方案: {}", e.getMessage());
                imageBase64 = generateSimpleCaptchaImage(code);
            }
            
            redisUtil.set(code.toLowerCase(), code.toLowerCase(), 5, TimeUnit.MINUTES); // 5分钟过期
            responseParam.setCode(code);
            responseParam.setCodeImage(imageBase64);
            
        } catch (Exception e) {
            throw new CommonException("生成验证码失败：" + e.getMessage());
        }
        
        return responseParam;
    }
    
    /**
     * 生成简单的验证码图片（备用方案）
     */
    private String generateSimpleCaptchaImage(String code) {
        try {
            // 创建一个简单的验证码图片，不依赖字体
            java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(120, 40, java.awt.image.BufferedImage.TYPE_INT_RGB);
            java.awt.Graphics2D g2d = image.createGraphics();
            
            // 设置背景色
            g2d.setColor(java.awt.Color.WHITE);
            g2d.fillRect(0, 0, 120, 40);
            
            // 绘制简单的验证码文字
            g2d.setColor(java.awt.Color.BLACK);
            g2d.setFont(new java.awt.Font("Monospaced", java.awt.Font.BOLD, 20));
            g2d.drawString(code, 30, 25);
            
            // 绘制干扰线
            g2d.setColor(java.awt.Color.LIGHT_GRAY);
            for (int i = 0; i < 3; i++) {
                int x1 = (int) (Math.random() * 120);
                int y1 = (int) (Math.random() * 40);
                int x2 = (int) (Math.random() * 120);
                int y2 = (int) (Math.random() * 40);
                g2d.drawLine(x1, y1, x2, y2);
            }
            
            g2d.dispose();
            
            // 转换为base64
            java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
            javax.imageio.ImageIO.write(image, "png", baos);
            byte[] imageBytes = baos.toByteArray();
            baos.close();
            
            String base64 = java.util.Base64.getEncoder().encodeToString(imageBytes);
            return "data:image/png;base64," + base64;
            
        } catch (Exception e) {
            log.error("生成简单验证码图片失败: {}", e.getMessage());
            // 如果连简单图片都生成失败，返回一个1x1的透明图片
            return "";
        }
    }

    @Override
    public StoreUser storeUserLogin(UserRequestParam requestParam) {
        StoreUser responseParam = new StoreUser();
        
        try {
            // 验证必填字段
            BizAssertUtil.notEmpty(requestParam.getCode(), 10003, "验证码不能为空");
            BizAssertUtil.notEmpty(requestParam.getAccount(), 10001, "账号不能为空");
            BizAssertUtil.notEmpty(requestParam.getPassword(), 10002, "密码不能为空");
            
            // 根据user_name查询业务员
            LambdaQueryWrapper<StoreUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(StoreUser::getUserName, requestParam.getAccount());
            queryWrapper.eq(StoreUser::getIsDelete, 0);
            StoreUser storeUser = storeUserMapper.selectOne(queryWrapper);
            
            if (storeUser == null) {
                throw new ServiceException("账号不存在");
            }

            // 验证密码（使用yoshop_hash加密）
            String encryptedPassword = PasswordUtil.yoshopHash(requestParam.getPassword());
            if (!encryptedPassword.equals(storeUser.getPassword())) {
                throw new ServiceException("密码错误");
            }

            // 验证验证码
            if (requestParam.getCode() != null && !requestParam.getCode().isEmpty()) {
                String redisCaptcha = (String) redisUtil.get(requestParam.getCode().toLowerCase());
                if (redisCaptcha == null || !requestParam.getCode().equalsIgnoreCase(redisCaptcha)) {
                    throw new ServiceException("验证码错误");
                }
                redisUtil.delete(requestParam.getCode().toLowerCase()); // 验证成功后删除验证码
            }


            // 使用Sa-Token登录（使用store_user_id作为登录ID）
            String token = SaTokenUtil.login(storeUser.getStoreUserId());
            
            // 更新业务员token到数据库
            storeUser.setToken(token);
            storeUserMapper.updateById(storeUser);
            BeanUtil.copyProperties(storeUser, responseParam);
            
        } catch (Exception e) {
            throw new CommonException("业务员登录失败：" + e.getMessage());
        }
        
        return responseParam;
    }

    @Override
    public StoreUserVo getStoreUserDetail() {
        StoreUserVo responseParam = new StoreUserVo();

        // 获取当前登录用户ID
        Long id = SaTokenUtil.getLoginId();
        if (id == null) {
            throw new ServiceException("用户未登录");
        }
        log.info("当前登录用户ID：{}", SaTokenUtil.getLoginUserType());
        // 判断是否为业务员登录
        if (SaTokenUtil.getLoginUserType() != SaTokenUtil.UserType.STORE_USER) {
            throw new ServiceException("当前用户不是业务员");
        }

        List<Long> rolelist = userMapper.isManager(id);
        List<StoreUser> storeUser = new ArrayList<>();
        if(rolelist.contains(10006L)){
            storeUser=storeUserMapper.selectList(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getParentId, id));
        }else{
            if(rolelist.contains(10007L)){
                storeUser.add(storeUserMapper.selectById(id));
            }
        }

        List<Long> idList=storeUser.stream().map(StoreUser::getStoreUserId).collect(Collectors.toList());
        BeanUtil.copyProperties(storeUserMapper.selectById(id), responseParam);
        List<User> list=new ArrayList<>();
        //不是业务员和业务主管开放所有数据权限
        if(!rolelist.contains(10006L)&&!rolelist.contains(10007L)){
            list = this.list();
        }else {
            list = this.list(new LambdaQueryWrapper<User>().in(User::getStoreUserId, idList));
        }
        if(list.isEmpty()){
            responseParam.setIsMessage(0L);
            return responseParam ;
        }
        List<Long> userIds=list.stream().map(User::getUserId).collect(Collectors.toList());
        Long count=orderService.count(new LambdaQueryWrapper<Order>().in(Order::getUserId,userIds).eq(Order::getAuditStatus, 0));
        responseParam.setIsMessage(count);

        return responseParam ;
    }

    @Override
    public CustomInfoResponseParam getCustomList(Page<User> page) {
        CustomInfoResponseParam responseParam = new CustomInfoResponseParam();

        // 获取当前登录用户ID
        Long id = SaTokenUtil.getLoginId();
        if (id == null) {
            throw new ServiceException("用户未登录");
        }

        List<Long> userIds = dataScopeInfo.getUserIds();

        // 根据用户类型设置不同的用户信息
        if (SaTokenUtil.isStoreUser()) {
            // 业务员：从StoreUser表中获取信息
            StoreUser storeUser = storeUserMapper.selectById(id);
            responseParam.setUser(storeUser);
        } else if (SaTokenUtil.isDealer()) {
            // 经销商：获取关联的业务员信息
            User dealer = this.getById(id);
            if (dealer != null && dealer.getStoreUserId() != null) {
                StoreUser storeUser = storeUserMapper.selectById(dealer.getStoreUserId());
                responseParam.setUser(storeUser);
            }
        }
        if(userIds.isEmpty()){
            page.setTotal(0);
            return responseParam;
        }
        Page<UserAddressVo> orderAddressListByStoreId = this.baseMapper.getOrderAddressListByStoreId(page, userIds);
        responseParam.setList(orderAddressListByStoreId);

        return responseParam;
    }

    @Override
    public void balanceApply(String money, String images) {
        try {
            balanceService.applyBalance(money,images);
        } catch (Exception e) {
            throw new CommonException("余额申请失败：" + e.getMessage());
        }
    }

    @Override
    public StatementAccountVo getStatementAccount(String startDate, String endDate) {
        try {
            // 获取用户ID列表
            List<Long> userIds = getUserIds();
            
            // 统计拿货金额（订单总金额）
            BigDecimal orderPrice = getOrderTotalPrice(startDate, endDate, userIds);
            
            // 统计可用余额
            BigDecimal balance = getUserBalance(userIds);
            
            // 统计充值金额
            BigDecimal balanceAll = getBalanceLogTotal(startDate, endDate, userIds);
            
            // 构建返回数据
            StatementAccountVo vo = new StatementAccountVo();
            vo.setOrderPrice(orderPrice);
            vo.setBalance(balance);
            vo.setBalanceAll(balanceAll);
            
            // 计算摘要
            StatementAccountVo.StatementSummary summary = new StatementAccountVo.StatementSummary();
            summary.setTotalAmount(balanceAll);
            summary.setNetAmount(balanceAll.subtract(orderPrice));
            vo.setSummary(summary);
            
            return vo;
            
        } catch (Exception e) {
            throw new CommonException("获取对账单失败：" + e.getMessage());
        }
    }
    
    /**
     * 获取用户ID列表
     */
    private List<Long> getUserIds() {
        List<Long> userIds = new ArrayList<>();

        // 获取当前登录用户ID
        Long loginId = SaTokenUtil.getLoginId();
        if (loginId == null) {
            return userIds;
        }

        // 判断用户类型
        if (SaTokenUtil.isStoreUser()) {
            // 业务员模式：获取业务员关联的所有经销商
            StoreUser storeUser1 = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreUserId, loginId));
            if (storeUser1 != null) {
                LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
                userWrapper.eq(User::getStoreUserId, storeUser1.getStoreUserId());
                List<User> users = userMapper.selectList(userWrapper);
                userIds = users.stream().map(User::getUserId).collect(Collectors.toList());
            }
        } else if (SaTokenUtil.isDealer()) {
            // 经销商模式：只查询当前用户
            User user = userMapper.selectById(loginId);
            if (user != null) {
                userIds.add(user.getUserId());
            } else {
                throw new CommonException("没有找到用户信息");
            }
        }

        return userIds;
    }
    
    /**
     * 获取订单总金额
     */
    private BigDecimal getOrderTotalPrice(String startDate, String endDate, List<Long> userIds) {
        if (userIds.isEmpty()) {
            return BigDecimal.ZERO;
        }
        
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Order::getUserId, userIds)
               .eq(Order::getPayStatus, 20)  // 已支付
               .ne(Order::getOrderStatus, 20) // 非已取消
               .eq(Order::getIsDelete, 0);    // 未删除
        
        // 时间范围查询
        if (startDate != null && endDate != null) {
            long startTime = java.time.LocalDate.parse(startDate).atStartOfDay().atZone(java.time.ZoneId.systemDefault()).toEpochSecond();
            long endTime = java.time.LocalDate.parse(endDate).atStartOfDay().atZone(java.time.ZoneId.systemDefault()).toEpochSecond() + 86400;
            
            wrapper.ge(Order::getPayTime, startTime)
                   .lt(Order::getPayTime, endTime);
        }
        
        List<Order> orders = orderService.list(wrapper);
        return orders.stream()
                .map(Order::getPayPrice)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
    
    /**
     * 获取用户余额
     */
    private BigDecimal getUserBalance(List<Long> userIds) {
        if (userIds.isEmpty()) {
            return BigDecimal.ZERO;
        }
        
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(User::getUserId, userIds);
        List<User> users = userMapper.selectList(wrapper);
        
        return users.stream()
                .map(User::getBalance)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
    
    /**
     * 获取充值总金额
     */
    private BigDecimal getBalanceLogTotal(String startDate, String endDate, List<Long> userIds) {
        if (userIds.isEmpty()) {
            return BigDecimal.ZERO;
        }

        LambdaQueryWrapper<UserBalanceLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(UserBalanceLog::getScene, 10,30)
                .in(UserBalanceLog::getUserId, userIds)
                .gt(UserBalanceLog::getMoney, 0);
        if (StringUtils.isNoneEmpty(startDate)) {
            // 解析 startDate
            long startTime = java.time.LocalDate.parse(startDate)
                    .atStartOfDay(java.time.ZoneId.systemDefault())
                    .toEpochSecond();

            wrapper.ge(UserBalanceLog::getCreateTime, startTime);
        }
        if(StringUtils.isNoneEmpty(endDate)){
            // 解析 endDate（加一天确保包含当天）
            long endTime = java.time.LocalDate.parse(endDate)
                    .atStartOfDay(java.time.ZoneId.systemDefault())
                    .toEpochSecond() + 86400;

            // 使用转换后的时间戳进行查询
            wrapper.lt(UserBalanceLog::getCreateTime, endTime);
        }
        List<UserBalanceLog> list = balanceService.list(wrapper);
        return list.stream()
                .map(UserBalanceLog::getMoney)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    @Override
    public void initializeSaToken() {
        log.info("Redis模式下无需手动初始化Sa-Token，token会自动持久化到Redis中");
        // Redis模式下，Sa-Token会自动将token存储到Redis中，无需手动加载
    }

    /**
     * 生成随机验证码
     */
    private String generateRandomCode(int length) {
        return PasswordUtil.generateRandomCode(length);
    }

    /**
     * 构建用户信息对象
     */
    private UserInfo buildUserInfo(User user) {
        UserInfo userInfo = new UserInfo();
        
        userInfo.setUserId(user.getUserId());
        userInfo.setStoreUserId(user.getStoreUserId());
        userInfo.setNickName(user.getNickName());
        userInfo.setAvatarUrl(user.getAvatarUrl());
        userInfo.setGender(user.getGender() != null ? (user.getGender() == 1 ? "男" : user.getGender() == 2 ? "女" : "未知") : "未知");
        userInfo.setCountry(user.getCountry());
        userInfo.setProvinceId(user.getProvinceId() != null ? user.getProvinceId().intValue() : null);
        userInfo.setCityId(user.getCityId() != null ? user.getCityId().intValue() : null);
        userInfo.setRegionId(user.getRegionId() != null ? user.getRegionId().intValue() : null);
        userInfo.setAddressId(user.getAddressId() != null ? user.getAddressId().intValue() : null);
        userInfo.setGradeId(user.getGradeId() != null ? user.getGradeId().intValue() : null);
        userInfo.setToken(user.getToken());
        userInfo.setMobile(user.getMobile());
        userInfo.setRealName(user.getRealName());
        userInfo.setAccount(user.getAccount());
        userInfo.setPassword(user.getPassword());

        // 设置省市区信息
        RegionInfo regionInfo = new RegionInfo();

        userInfo.setRegion(regionInfo);

        return userInfo;
    }
    
    /**
     * 构建业务员信息
     */
    private UserInfo buildStoreUserInfo(StoreUser storeUser) {
        UserInfo userInfo = new UserInfo();
        userInfo.setStoreUserId(storeUser.getStoreUserId());
        userInfo.setNickName(storeUser.getRealName()); // 业务员使用真实姓名作为昵称
        userInfo.setRealName(storeUser.getRealName());
        userInfo.setMobile(storeUser.getMobile());
        userInfo.setAccount(storeUser.getUserName());
        userInfo.setToken(storeUser.getToken());
        userInfo.setProvinceId(storeUser.getProvinceId() != null ? storeUser.getProvinceId().intValue() : null);
        userInfo.setCityId(storeUser.getCityId() != null ? storeUser.getCityId().intValue() : null);
        userInfo.setRegionId(storeUser.getRegionId() != null ? storeUser.getRegionId().intValue() : null);
        
        return userInfo;
    }

    @Override
    public StoreUserLoginVo storeLogin(UserRequestParam requestParam) {
        try {
            // 验证必填字段
            BizAssertUtil.notEmpty(requestParam.getAccount(), 10001, "用户名不能为空");
            BizAssertUtil.notEmpty(requestParam.getPassword(), 10002, "密码不能为空");
            BizAssertUtil.notEmpty(requestParam.getCode(), 10003, "验证码不能为空");
            // 根据用户名查询用户
            LambdaQueryWrapper<StoreUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(StoreUser::getUserName, requestParam.getAccount());
            queryWrapper.eq(StoreUser::getIsDelete, 0);
            StoreUser storeUser = storeUserMapper.selectOne(queryWrapper);
            
            if (storeUser == null) {
                throw new ServiceException("账号不存在");
            }

            // 检查登录失败次数限制
            if (storeUser.getLoginFailureCount() >= 3) {
                // 检查是否在24小时内
                long currentTime = System.currentTimeMillis() / 1000;
                if (storeUser.getUpdateTime() != null && 
                    (currentTime - storeUser.getUpdateTime()) < 86400) {
                    throw new ServiceException("请于1天后再尝试登录");
                }
            }

            // 验证密码（使用yoshop_hash加密）
            String encryptedPassword = PasswordUtil.yoshopHash(requestParam.getPassword());
            if (!encryptedPassword.equals(storeUser.getPassword())) {
                // 更新登录失败次数
                int newFailureCount = storeUser.getLoginFailureCount() + 1;
                storeUserMapper.updateLoginFailure(storeUser.getStoreUserId(), newFailureCount);
                throw new ServiceException("密码错误");
            }

            // 验证验证码（如果提供）
            if (requestParam.getCode() != null && !requestParam.getCode().isEmpty()) {
                String redisCaptcha = (String) redisUtil.get(requestParam.getCode().toLowerCase());
                if (redisCaptcha == null || !requestParam.getCode().equalsIgnoreCase(redisCaptcha)) {
                    throw new ServiceException("验证码错误");
                }
                redisUtil.delete(requestParam.getCode().toLowerCase()); // 验证成功后删除验证码
            }

            // 使用Sa-Token登录
            String token = SaTokenUtil.login(storeUser.getStoreUserId());
            // 更新用户登录信息
            String currentTime = String.valueOf(System.currentTimeMillis() / 1000);
            String clientIp = getClientIp();
            updateLoginInfo(storeUser.getStoreUserId(), currentTime, clientIp, 0);
            // 获取用户角色
            List<StoreRole> roles = getStoreUserRoles(storeUser.getStoreUserId());
            
            // 获取用户权限
            List<StoreAccess> permissions = getStoreUserPermissions(storeUser.getStoreUserId());
            
            // 获取用户菜单
            List<StoreUserLoginVo.MenuVo> menus = getStoreUserMenus(storeUser.getStoreUserId());
            
            // 构建返回数据
            StoreUserLoginVo loginVo = new StoreUserLoginVo();
            loginVo.setToken(token);
            loginVo.setUser(storeUser);
            loginVo.setRoles(roles);
            loginVo.setPermissions(permissions);
            loginVo.setMenus(menus);
            
            return loginVo;
            
        } catch (Exception e) {
            throw new ServiceException("登录失败：" + e.getMessage());
        }
    }

    // 门店后台-管理员用户分页（新方法名避免与现有冲突）
    @Override
    public Page<StoreUserListItemVo> getStoreAdminUserPage(StoreUserListRequest request, Page<StoreUserListItemVo> page,String userName) {
        long total = userMapper.countStoreAdminUsers(request.getRoleType(), request.getParentId(), request.getKeyword(), userName);
        if (total <= 0) {
            page.setTotal(0);
            page.setRecords(java.util.Collections.emptyList());
            return page;
        }
        int offset = (int) ((page.getCurrent() - 1) * page.getSize());
        java.util.List<StoreUserListItemVo> records = userMapper.selectStoreAdminUserPage(
                request.getRoleType(), request.getParentId(), request.getKeyword(), userName, offset, (int) page.getSize());
        page.setTotal(total);
        page.setRecords(records);
        return page;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createStoreAdminUser(StoreUserSaveRequest request) {
        BizAssertUtil.notEmpty(request.getUserName(), 10001, "用户名不能为空");
        BizAssertUtil.notEmpty(request.getPassword(), 10002, "密码不能为空");
        BizAssertUtil.notEmpty(request.getPasswordConfirm(), 10003, "确认密码不能为空");
        if (!request.getPassword().equals(request.getPasswordConfirm())) {
            throw new ServiceException("确认密码不正确");
        }
        // 用户名唯一
        Long cnt = storeUserMapper.selectCount(new LambdaQueryWrapper<StoreUser>()
                .eq(StoreUser::getUserName, request.getUserName())
                .eq(StoreUser::getIsDelete, 0));
        if (cnt != null && cnt > 0) {
            throw new ServiceException("用户名已存在");
        }

        // 新增用户
        StoreUser su = new StoreUser();
        su.setUserName(request.getUserName());
        su.setRealName(request.getRealName());
        su.setParentId(request.getParentId() != null ? request.getParentId().intValue() : null);
        su.setMobile(request.getMobile());
        su.setPassword(PasswordUtil.yoshopHash(request.getPassword()));
        // 设置地域信息
//        su.setProvinceId(request.getProvinceId().intValue());
//        su.setCityId(request.getCityId().intValue());
//        su.setRegionId(request.getRegionId().intValue());
        su.setIsDelete(0);
        su.setIsSuper(0);
        su.setUpdateTime(System.currentTimeMillis() /1000);
        su.setCreateTime(System.currentTimeMillis() /1000);
        storeUserMapper.insert(su);
        //配送表
        storeUserMapper.insertUserRole(su.getStoreUserId(),request.getAddress(),System.currentTimeMillis() /1000);
        // 角色关系
        if (request.getRoleIds() != null && !request.getRoleIds().isEmpty()) {
            if(request.getRoleIds().contains(10007L)){
                BizAssertUtil.notNull(request.getParentId(), 10008, "请选择上级主管");
            }
            storeUserRoleMapper.batchInsert(su.getStoreUserId(), request.getRoleIds());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStoreAdminUser(StoreUserSaveRequest request) {
        BizAssertUtil.notNull(request.getStoreUserId(), 10004, "用户ID不能为空");
        StoreUser exist = storeUserMapper.selectById(request.getStoreUserId());
        if (exist == null || (exist.getIsDelete() != null && exist.getIsDelete() == 1)) {
            throw new ServiceException("用户不存在");
        }
        // 用户名唯一检查
        if (org.apache.commons.lang3.StringUtils.isNotBlank(request.getUserName())
                && !request.getUserName().equals(exist.getUserName())) {
            Long cnt = storeUserMapper.selectCount(new LambdaQueryWrapper<StoreUser>()
                    .eq(StoreUser::getUserName, request.getUserName())
                    .eq(StoreUser::getIsDelete, 0));
            if (cnt != null && cnt > 0) {
                throw new ServiceException("用户名已存在");
            }
        }
        // 更新基本信息
        StoreUser upd = new StoreUser();
        upd.setStoreUserId(request.getStoreUserId());
        if (org.apache.commons.lang3.StringUtils.isNotBlank(request.getUserName())) {
            upd.setUserName(request.getUserName());
        }
        if (org.apache.commons.lang3.StringUtils.isNotBlank(request.getRealName())) {
            upd.setRealName(request.getRealName());
        }
        if (request.getParentId() != null) {
            upd.setParentId(request.getParentId().intValue());
        }
        // 更新地域信息
        this.baseMapper.updateStoreUserRegion(request.getStoreUserId(), request.getAddress());

        if (org.apache.commons.lang3.StringUtils.isNotBlank(request.getPassword())) {
            if (!request.getPassword().equals(request.getPasswordConfirm())) {
                throw new ServiceException("确认密码不正确");
            }
            upd.setPassword(PasswordUtil.yoshopHash(request.getPassword()));
        }

        LambdaUpdateWrapper<StoreUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper=vaildUpdate(request, updateWrapper);
        storeUserMapper.update(updateWrapper);
        // 角色更新：先删后插
        if (request.getRoleIds() != null) {
            storeUserRoleMapper.deleteByUserId(request.getStoreUserId());
            if (!request.getRoleIds().isEmpty()) {
                storeUserRoleMapper.batchInsert(request.getStoreUserId(), request.getRoleIds());
            }
        }
    }

    private LambdaUpdateWrapper<StoreUser> vaildUpdate(StoreUserSaveRequest request, LambdaUpdateWrapper<StoreUser> updateWrapper) {
        updateWrapper.eq(StoreUser::getStoreUserId, request.getStoreUserId());

        // 只更新非空字段
        if (org.apache.commons.lang3.StringUtils.isNotBlank(request.getUserName())) {
            updateWrapper.set(StoreUser::getUserName, request.getUserName());
        }
        if (org.apache.commons.lang3.StringUtils.isNotBlank(request.getRealName())) {
            updateWrapper.set(StoreUser::getRealName, request.getRealName());
        }
        if (org.apache.commons.lang3.StringUtils.isNotBlank(request.getPassword())) {
            updateWrapper.set(StoreUser::getPassword, PasswordUtil.yoshopHash(request.getPassword()));
        }
        if (request.getProvinceId() != null) {
            updateWrapper.set(StoreUser::getProvinceId, request.getProvinceId());
        }
        if (request.getCityId() != null) {
            updateWrapper.set(StoreUser::getCityId, request.getCityId());
        }
        if (request.getRegionId() != null) {
            updateWrapper.set(StoreUser::getRegionId, request.getRegionId());
        }
        if (request.getParentId() != null) {
            updateWrapper.set(StoreUser::getParentId, request.getParentId());
        }
        return updateWrapper;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteStoreAdminUser(Long storeUserId) {
        BizAssertUtil.notNull(storeUserId, 10004, "用户ID不能为空");
        StoreUser exist = storeUserMapper.selectById(storeUserId);
        if (exist == null || (exist.getIsDelete() != null && exist.getIsDelete() == 1)) {
            return; // 视为已删除
        }
        if (exist.getIsSuper() != null && exist.getIsSuper() == 1) {
            throw new ServiceException("超级管理员不允许删除");
        }
        // 软删用户
        storeUserMapper.deleteById(storeUserId);
        // 删除角色关系
        storeUserRoleMapper.deleteByUserId(storeUserId);
    }

    private void updateLoginInfo(Long storeUserId, String currentTime, String clientIp, int i) {
        LambdaUpdateWrapper<StoreUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(StoreUser::getLoginTime, currentTime);
        updateWrapper.set(StoreUser::getLoginip, clientIp);
        updateWrapper.set(StoreUser::getLoginfailure, i);
        updateWrapper.eq(StoreUser::getStoreUserId, storeUserId);
        storeUserMapper.update(null, updateWrapper);
    }

    /**
     * 获取用户角色列表
     */
    private List<StoreRole> getStoreUserRoles(Long storeUserId) {
        // 获取用户角色ID列表
        List<Long> roleIds = storeUserRoleMapper.selectRoleIdsByUserId(storeUserId);
        if (roleIds.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 根据角色ID查询角色信息
        return storeRoleMapper.selectRolesByIds(roleIds);
    }

    /**
     * 获取用户权限列表
     */
    private List<StoreAccess> getStoreUserPermissions(Long storeUserId) {
        // 获取用户角色ID列表
        List<Long> roleIds = storeUserRoleMapper.selectRoleIdsByUserId(storeUserId);
        if (roleIds.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 根据角色ID获取权限ID列表
        List<Long> accessIds = storeRoleAccessMapper.selectAccessIdsByRoleIds(roleIds);
        if (accessIds.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 根据权限ID查询权限信息
        return storeAccessMapper.selectAccessByIds(accessIds);
    }

    /**
     * 获取所有权限（用于构建菜单树结构）
     */
    private List<StoreAccess> getAllPermissions() {
        // 获取所有有效的权限，用于构建完整的菜单树结构
        return storeAccessMapper.selectAllValidAccess();
    }

    /**
     * 获取用户菜单列表
     */
    private List<StoreUserLoginVo.MenuVo> getStoreUserMenus(Long storeUserId) {
        // 获取用户权限列表（用于判断哪些权限是用户拥有的）
        List<StoreAccess> userPermissions = getStoreUserPermissions(storeUserId);

        // 获取所有权限（用于构建完整的菜单树结构）
        List<StoreAccess> allPermissions = getAllPermissions();

        // 构建菜单树
        List<StoreUserLoginVo.MenuVo> menuTree = buildMenuTree(userPermissions, allPermissions);
        return menuTree;
    }

    /**
     * 构建正确的菜单树（基于父权限判断菜单/按钮）
     * @param userPermissions 用户拥有的权限列表
     * @param allPermissions 系统所有权限列表
     */
    private List<StoreUserLoginVo.MenuVo> buildMenuTree(List<StoreAccess> userPermissions, List<StoreAccess> allPermissions) {
        List<StoreUserLoginVo.MenuVo> menuList = new ArrayList<>();

        // 创建用户权限ID集合（用于判断用户是否拥有某个权限）
        Set<Long> userAccessIds = new HashSet<>();
        for (StoreAccess access : userPermissions) {
            userAccessIds.add(access.getAccessId());
        }

        // 创建所有权限映射（包含完整的权限结构）
        Map<Long, StoreAccess> allAccessMap = new HashMap<>();
        for (StoreAccess access : allPermissions) {
            allAccessMap.put(access.getAccessId(), access);
        }

        // 找出所有菜单类型的权限节点
        // 核心逻辑：如果权限的父ID在用户的权限列表中，则认为是按钮权限，不显示在菜单中
        // 如果权限的父ID不在用户的权限列表中，则认为是菜单权限，需要显示
        Set<Long> menuAccessIds = new HashSet<>();
        Set<Long> buttonAccessIds = new HashSet<>();

        for (StoreAccess access : userPermissions) {
            boolean hasParentInUserPermissions = access.getParentId() != null &&
                                                access.getParentId() != 0 &&
                                                userAccessIds.contains(access.getParentId());

            if (hasParentInUserPermissions) {
                // 父权限在用户权限列表中，认为是按钮权限
                buttonAccessIds.add(access.getAccessId());
            } else {
                // 父权限不在用户权限列表中（或为顶级），认为是菜单权限
                menuAccessIds.add(access.getAccessId());
            }
        }

        // 调试日志
        log.info("权限统计: 用户权限={}, 菜单权限={}, 按钮权限={}",
                userAccessIds.size(), menuAccessIds.size(), buttonAccessIds.size());

        // 菜单节点ID集合（扁平结构只需要菜单节点，不需要递归查找父节点）
        Set<Long> visibleAccessIds = new HashSet<>(menuAccessIds);

        log.info("最终可见权限数量: {}", visibleAccessIds.size());

        // 构建菜单映射（只包含真实存在的权限）
        Map<Long, StoreUserLoginVo.MenuVo> menuMap = new HashMap<>();
        for (Long accessId : visibleAccessIds) {
            StoreAccess access = allAccessMap.get(accessId);
            if (access != null) {
                StoreUserLoginVo.MenuVo menu = new StoreUserLoginVo.MenuVo();
                menu.setMenuId(access.getAccessId());
                menu.setMenuName(access.getName());
                menu.setMenuUrl(access.getUrl());
                menu.setClickable(access.hasValidUrl());
                menu.setSort(access.getSort());
                // 扁平结构不需要children字段

                menuMap.put(access.getAccessId(), menu);
            }
        }

        // 构建扁平结构的菜单列表（所有菜单都在第一层，通过parentId建立关系）
        for (Long accessId : visibleAccessIds) {
            StoreAccess access = allAccessMap.get(accessId);
            if (access != null) {
                StoreUserLoginVo.MenuVo menu = menuMap.get(access.getAccessId());
                if (menu != null) {
                    // 设置parentId，让前端可以构建树状结构
                    menu.setParentId(access.getParentId());
                    menuList.add(menu);
                }
            }
        }

        // 对菜单列表进行排序
        menuList.sort((a, b) -> {
            // 首先按parentId排序（顶级菜单排在前面）
            int parentCompare = Long.compare(
                a.getParentId() != null ? a.getParentId() : 0,
                b.getParentId() != null ? b.getParentId() : 0
            );
            if (parentCompare != 0) {
                return parentCompare;
            }
            // 然后按sort字段排序
            return Integer.compare(
                a.getSort() != null ? a.getSort() : 100,
                b.getSort() != null ? b.getSort() : 100
            );
        });

        return menuList;
    }






    /**
     * 对菜单列表进行排序（扁平结构）
     */
    private void sortMenuList(List<StoreUserLoginVo.MenuVo> menuList) {
        if (menuList == null || menuList.isEmpty()) {
            return;
        }

        // 扁平结构直接排序
        menuList.sort((a, b) -> Integer.compare(
            a.getSort() != null ? a.getSort() : 100,
            b.getSort() != null ? b.getSort() : 100
        ));
    }

    /**
     * 获取客户端IP地址
     */
    private String getClientIp() {
        // 这里可以从HttpServletRequest中获取真实IP
        // 暂时返回默认值
        return "127.0.0.1";
    }

    @Override
    public List<RoleListItemVo> getRoleList(String roleName) {
        return userMapper.selectRoleList(roleName);
    }

    @Override
    public List<ManagerListItemVo> getManagerList() {
        return userMapper.selectManagerList();
    }

    @Override
    public String alterTable(int type) {
        if(type == 1){
            // 分别执行两次重命名
//            userMapper.renameNickNameColumn("nick_name", "nickName");
//            userMapper.renameAvatarUrlColumn("avatar_url", "avatarUrl");
            userMapper.changeToPC();
        }
        if(type == 2){
            // 反向重命名
//            userMapper.renameNickNameColumn("nickName", "nick_name");
//            userMapper.renameAvatarUrlColumn("avatarUrl", "avatar_url");
            userMapper.changeToApp();
        }
        return "success";
    }

    @Override
    public UserAddressVo getDefaultAddress(Long userId) {
        try {
            // 获取用户信息
            User user = this.getById(userId);
            if (user == null) {
                return null;
            }

            // 如果用户有默认地址ID，则获取该地址信息
            if (user.getAddressId() != null && user.getAddressId() != 0) {
                // 获取用户的默认收货地址
                AddressInfo addressInfo = userAddressMapper.getAddressDetailById(user.getAddressId().longValue());
                if (addressInfo != null) {
                    // 转换为UserAddressVo类型，包含用户信息和地址信息
                    UserAddressVo userAddressVo = new UserAddressVo();
                    // 复制用户信息到UserAddressVo
                    BeanUtil.copyProperties(user, userAddressVo);
                    // 设置地址相关的region信息
                    userAddressVo.setRegion(addressInfo.getRegion());
                    return userAddressVo;
                }
            }

            return null;
        } catch (Exception e) {
            log.error("获取用户默认地址失败，用户ID: {}", userId, e);
            return null;
        }
    }

    @Override
    public StoreDetail getStoreUserDetailById(Long storeId) {
        StoreDetail storeDetail = new StoreDetail();
        StoreUser storeUser = storeUserMapper.selectById(storeId);
        BeanUtil.copyProperties(storeUser, storeDetail);
        StoreUserRule storeUserRule = storeUserRuleMapper.selectOne(new LambdaQueryWrapper<StoreUserRule>().eq(StoreUserRule::getStoreUserId, storeId.intValue()));
        if(storeUserRule != null && storeUserRule.getRegion() != null){
            String[] split = storeUserRule.getRegion().split(",");
            storeDetail.setAddressId(split);
        }
        List<StoreUserRole> storeUserRole = storeUserRoleMapper.selectList(new LambdaQueryWrapper<StoreUserRole>().eq(StoreUserRole::getStoreUserId, storeId.intValue()));
       if(storeUserRole != null && storeUserRole.size() > 0){
           List<Long> collect = storeUserRole.stream().map(StoreUserRole::getRoleId).collect(Collectors.toList());
           storeDetail.setRoleId(collect);
       }
        storeDetail.setManagerId(storeUser.getParentId().longValue());
        return storeDetail;
    }

    @Override
    public void updateStoreUser(StoreUser user) {
        BizAssertUtil.notNull(user.getStoreUserId(), 10001, "id不能为空");
        if(StringUtils.isNotBlank(user.getPassword())) {
            user.setPassword(PasswordUtil.yoshopHash(user.getPassword()));
        }
        storeUserMapper.updateById(user);
    }
} 